package com.du.quant.util;

import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 内存缓存工具类（静态类）
 * 支持过期时间设置和自动清理
 */
@Slf4j
public final class MemoryCache {

    // 私有构造函数，防止实例化
    private MemoryCache() {
        throw new UnsupportedOperationException("这是一个工具类，不需要实例化");
    }

    // 缓存存储结构
    private static final Map<String, CacheItem> CACHE = new ConcurrentHashMap<>();

    // 读写锁，保证线程安全
    private static final ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();

    // 定时清理任务执行器
    private static final ScheduledExecutorService CLEANUP_EXECUTOR =
            Executors.newSingleThreadScheduledExecutor(r -> {
                Thread t = new Thread(r, "MemoryCache-Cleanup");
                t.setDaemon(true); // 设置为守护线程，不会阻止JVM关闭
                return t;
            });

    // 默认缓存时间（毫秒）- 30分钟
    private static final long DEFAULT_EXPIRE_TIME = 30 * 60 * 1000;

    // 清理间隔（毫秒）- 1分钟
    private static final long CLEANUP_INTERVAL = 60 * 1000;

    // 静态初始化块，启动清理任务
    static {
        startCleanupTask();

        // 注册JVM关闭钩子，优雅关闭
        Runtime.getRuntime().addShutdownHook(new Thread(MemoryCache::shutdown));
    }

    /**
     * 缓存项内部类
     */
    private static class CacheItem {
        private final Object value;
        private final long expireTime;
        private final long createTime;

        public CacheItem(Object value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
            this.createTime = System.currentTimeMillis();
        }

        public boolean isExpired() {
            return System.currentTimeMillis() > expireTime;
        }

        public long getRemainingTime() {
            return Math.max(0, expireTime - System.currentTimeMillis());
        }
    }

    /**
     * 启动定时清理任务
     */
    private static void startCleanupTask() {
        CLEANUP_EXECUTOR.scheduleAtFixedRate(MemoryCache::cleanupExpiredItems,
                CLEANUP_INTERVAL, CLEANUP_INTERVAL, TimeUnit.MILLISECONDS);
    }

    /**
     * 清理过期缓存项
     */
    private static void cleanupExpiredItems() {
        LOCK.writeLock().lock();
        try {
            int initialSize = CACHE.size();
            CACHE.entrySet().removeIf(entry -> entry.getValue().isExpired());
            int finalSize = CACHE.size();
            int cleanedCount = initialSize - finalSize;
            if (cleanedCount > 0) {
                log.info("MemoryCache 清理完成: " + cleanedCount + " 个过期项被清理");
            }
        } finally {
            LOCK.writeLock().unlock();
        }
    }

    /**
     * 添加缓存（使用默认过期时间）
     * @param key 缓存键
     * @param value 缓存值
     */
    public static void put(String key, Object value) {
        put(key, value, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 添加缓存（自定义过期时间）
     * @param key 缓存键
     * @param value 缓存值
     * @param expireTime 过期时间（毫秒）
     */
    public static void put(String key, Object value, long expireTime) {
        if (key == null || value == null) {
            throw new IllegalArgumentException("Key和Value不能为null");
        }

        if (expireTime <= 0) {
            throw new IllegalArgumentException("过期时间必须大于0");
        }

        long actualExpireTime = System.currentTimeMillis() + expireTime;
        CacheItem item = new CacheItem(value, actualExpireTime);

        LOCK.writeLock().lock();
        try {
            CACHE.put(key, item);
        } finally {
            LOCK.writeLock().unlock();
        }
    }

    /**
     * 获取缓存值
     * @param key 缓存键
     * @return 缓存值，如果不存在或已过期则返回null
     */
    public static Object get(String key) {
        if (key == null) {
            return null;
        }

        LOCK.readLock().lock();
        try {
            CacheItem item = CACHE.get(key);
            if (item == null) {
                return null;
            }

            // 检查是否过期
            if (item.isExpired()) {
                // 异步移除过期项
                removeAsync(key);
                return null;
            }

            return item.value;
        } finally {
            LOCK.readLock().unlock();
        }
    }

    /**
     * 获取缓存值（指定类型）
     * @param key 缓存键
     * @param clazz 期望的类型
     * @return 指定类型的缓存值，如果类型不匹配返回null
     */
    @SuppressWarnings("unchecked")
    public static <T> T get(String key, Class<T> clazz) {
        Object value = get(key);
        if (value != null && clazz.isInstance(value)) {
            return (T) value;
        }
        return null;
    }

    /**
     * 异步移除缓存项
     */
    private static void removeAsync(String key) {
        new Thread(() -> remove(key)).start();
    }

    /**
     * 移除缓存项
     * @param key 缓存键
     * @return 被移除的值，如果不存在返回null
     */
    public static Object remove(String key) {
        if (key == null) {
            return null;
        }

        LOCK.writeLock().lock();
        try {
            CacheItem item = CACHE.remove(key);
            return item != null ? item.value : null;
        } finally {
            LOCK.writeLock().unlock();
        }
    }

    /**
     * 检查缓存是否存在且未过期
     * @param key 缓存键
     * @return 是否存在
     */
    public static boolean contains(String key) {
        return get(key) != null;
    }

    /**
     * 获取缓存剩余存活时间
     * @param key 缓存键
     * @return 剩余时间（毫秒），-1表示不存在，0表示已过期
     */
    public static long getRemainingTime(String key) {
        if (key == null) {
            return -1;
        }

        LOCK.readLock().lock();
        try {
            CacheItem item = CACHE.get(key);
            if (item == null) {
                return -1;
            }
            return item.getRemainingTime();
        } finally {
            LOCK.readLock().unlock();
        }
    }

    /**
     * 清空所有缓存
     */
    public static void clear() {
        LOCK.writeLock().lock();
        try {
            CACHE.clear();
        } finally {
            LOCK.writeLock().unlock();
        }
    }

    /**
     * 获取缓存大小（包含过期但未清理的项）
     * @return 缓存项数量
     */
    public static int size() {
        LOCK.readLock().lock();
        try {
            return CACHE.size();
        } finally {
            LOCK.readLock().unlock();
        }
    }

    /**
     * 获取有效缓存大小（不包含过期项）
     * @return 有效缓存项数量
     */
    public static int validSize() {
        LOCK.readLock().lock();
        try {
            return (int) CACHE.values().stream()
                    .filter(item -> !item.isExpired())
                    .count();
        } finally {
            LOCK.readLock().unlock();
        }
    }

    /**
     * 关闭缓存，释放资源
     * 注意：通常不需要手动调用，JVM关闭时会自动调用
     */
    public static void shutdown() {
        CLEANUP_EXECUTOR.shutdown();
        try {
            if (!CLEANUP_EXECUTOR.awaitTermination(3, TimeUnit.SECONDS)) {
                CLEANUP_EXECUTOR.shutdownNow();
            }
        } catch (InterruptedException e) {
            CLEANUP_EXECUTOR.shutdownNow();
            Thread.currentThread().interrupt();
        }
        clear();
    }

    /**
     * 获取缓存统计信息
     */
    public static String getStats() {
        int total = size();
        int valid = validSize();
        return String.format("MemoryCache统计: 总数=%d, 有效=%d, 过期=%d", total, valid, total - valid);
    }

    /**
     * 设置默认过期时间（毫秒）
     * 注意：这不会影响已存在的缓存项
     * @param expireTime 新的默认过期时间
     */
    public static void setDefaultExpireTime(long expireTime) {
        if (expireTime <= 0) {
            throw new IllegalArgumentException("默认过期时间必须大于0");
        }
        // 由于DEFAULT_EXPIRE_TIME是final的，这里需要重新设计
        // 在实际使用中，可以通过配置类来管理，这里保持简单
        log.info("注意：静态工具类的默认过期时间需要在编译期确定");
    }
}
